/*
This is part of Screenbar, which is based in part on the Litestep
shell source code.

Copyright (C) 2008-2009 Jim Babcock
Copyright (C) 1997-2009 The LiteStep Development Team

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/
#pragma once

class Animation
{
public:
	Animation(string prefix);
	
	virtual void apply(AnimationState *state, HDC source, HDC dest, int x, int y, int width, int height);
	virtual float getAlpha(AnimationState *state);
	virtual ElementSize getElementSize(AnimationState *state, ElementSize childSize);
	
	bool isFinished(AnimationState *state);
	int getDuration();
	string getPrefix();
	
	/// Certain animations require a transparent surface to paint on. For
	/// slide effects, color-key transparency is sufficient. For fade effects,
	/// an alpha blended surface is required.
	enum RequiredTransparency {
		transAny,
		transColorKey,
		transAlpha,
	};
	virtual RequiredTransparency getRequiredTransparency();
	virtual bool requiresTransfer();
	
	virtual int reverseTimeOffset(Animation *reverseAnimation, int timeOffset);
	
protected:
	string prefix;
	Direction direction;
	int duration; //(in milliseconds)
};

/////////////////////////////////////////////////////////////////////////////

class AnimationState
{
public:
	AnimationState();
	void updateTime();
	
	Animation *animation;
	Direction direction;
	int trigger;
	UINT64 startTime; //(in 100ns intervals)
	int timeOffset; //(in milliseconds)
};

/////////////////////////////////////////////////////////////////////////////

class AnimationPool
{
public:
	AnimationPool();
	~AnimationPool();
	
	Animation *getAnimation(string prefix);
	
private:
	Animation *createAnimation(string prefix);
	
	map<string, Animation*> animations;
};
extern AnimationPool *animationPool;

/////////////////////////////////////////////////////////////////////////////

class NullAnimation
	:public Animation
{
public:
	NullAnimation(string prefix);
};

/////////////////////////////////////////////////////////////////////////////

class SequenceAnimation
	:public Animation
{
public:
	SequenceAnimation(string prefix);
	
	void apply(AnimationState *state, HDC source, HDC dest, int x, int y, int width, int height);
	float getAlpha(AnimationState *state);
	RequiredTransparency getRequiredTransparency();
	ElementSize getElementSize(AnimationState *state, ElementSize childSize);
	
protected:
	pair<int,Animation*> getSequencePos(AnimationState *state);
	
	bool cyclic;
	vector<Animation*> children;
};

/////////////////////////////////////////////////////////////////////////////

class FadeAnimation
	:public Animation
{
public:
	FadeAnimation(string prefix, bool fadeIn);
	
	void apply(AnimationState *state, HDC source, HDC dest, int x, int y, int width, int height);
	float getAlpha(AnimationState *state);
	RequiredTransparency getRequiredTransparency();
	
protected:
	bool fadeIn;
};

/////////////////////////////////////////////////////////////////////////////

class SlideAnimation
	:public Animation
{
public:
	SlideAnimation(string prefix, bool slideIn);
	
	void apply(AnimationState *state, HDC source, HDC dest, int x, int y, int width, int height);
	RequiredTransparency getRequiredTransparency();
	
protected:
	bool slideIn;
};

/////////////////////////////////////////////////////////////////////////////

class ShiftAnimation
	:public Animation
{
public:
	ShiftAnimation(string prefix, bool enlarge);
	void apply(AnimationState *state, HDC source, HDC dest, int x, int y, int width, int height);
	ElementSize getElementSize(AnimationState *state, ElementSize baseSize);
	
protected:
	bool enlarge;
};
